package ch.unisi.inf.java.project.riskbami.model;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
/**
 * Class Country to model the countries in the game.
 * 
 * @author minellir@lu.unisi.ch
 * @author babazadm@lu.unisi.ch
 */
public class Country {
    private final String name;
    private int armies;
    private ArrayList<Country> nearbyCountries;
    private final Random dice = new Random();
    private final ArrayList<CountryListener> listeners;
    
    /**
     * Constructor for the class Country
     * At creation time the number of armies is set to 0 and the ArrayList<Country> of
     * nearby countries is set to null.
     * @param String The name of the country
     */
    public Country(final String name) {       
        this.nearbyCountries = new ArrayList<Country>();
        this.name = name;
        this.armies = 0;
        this.listeners = new ArrayList<CountryListener>();
    }

    /**
     * addArmies adds a number of armies to this territory
     * 
     * @param number The number of armies to add to this territory
     */
    public final void addArmies(final int number){
        this.armies += number;
        fireArmiesChanged(this);
    }
    
    /**
     * removeArmies removes a number of armies to this territory, if < 0 then set to 0.
     * 
     * @param number The number of armies to add to this territory
     */
    public final void removeArmies(final int number){
        final int newNumber = this.armies - number;
        if(newNumber<0) {
            this.armies = 0;
           } else { this.armies= newNumber; }
        fireArmiesChanged(this);
    }
    
    /**
     * getNumberOfArmies gives back the number of armies situated on a specific country.
     * 
     * @return int Number of armies.
     */
    public final int getNumberOfArmies(){
        return armies;
    }
    
    /**
     * getNearbyCountries gives back the Country[] of neighbors
     * 
     * @return ArrayList<Country> array of nearby countries.
     */
    public final ArrayList<Country> getNearbyCountries() {
        return nearbyCountries;
    }
    
    /**
     * containsNeighborsName
     * 
     * @return boolean True if this country contains the neighbor with the given name
     */
    public final boolean containsNeighborsName(final String neighborsName) {
        boolean contains = false;
        final ArrayList<Country> neighbors = this.getNearbyCountries();
        if(neighbors != null){
        for(final Country c : neighbors){
            if(c.getName().equals(neighborsName)){
                contains = true;
            }
        }
    }
        return contains;
    }

    /**
     * getName gives back the name of this country
     * 
     * @return String The name of this country.
     */
    public final String getName() {
        return name;
    }
    
    /**
     * setNearby set the nearby countries of a territory
     * 
     * @param nearby The array of neighbors countries.
     */
    public final void setNearby(final ArrayList<Country> nearby) {
        this.nearbyCountries = nearby;
    }
    
    /**
     * addNearby add the given nearby country of a territory
     * 
     * @param nearby The Country to add
     */
    public final Country addNearby(final Country neighbor) {
        this.nearbyCountries.add(neighbor);
        return this;
    }
    
    /**
     * toString implementation for the class Country.
     * 
     * @return String The name of the contries
     */
    public final String toString(){
        String toPrint = this.getName(); 
        return toPrint;
    }
       
    /**
     * revert is a private method that returns an array with elements starting from the end.
     * 
     * @param original The original array (of ints)
     * @return int[] The reverted copy of the array
     */
    private final int[] revert(final int[] original){
        final int[] reverted = new int[original.length];
        int count = 0;
        for(int i = reverted.length - 1; i>=0; i--){
            reverted[count] = original[i];
            count++;
        }
    return reverted;
    }
    
    /**
     * attackCountry contains the conflict simulator engine.
     * The simulation is done in according with the original rules of
     * the board game and contains an hidden dice generation.
     * 
     * @param defender The country to attack
     */
    public final void attackCountry(final Country defender){
        // some useful local variables
        int defLost = 0;
        int atkLost = 0;
        int defArmies = defender.getNumberOfArmies();
        int atkArmies = this.getNumberOfArmies();
        int[] defDices = new int[] {0, 0, 0};
        int[] atkDices = new int[] {0, 0, 0};
        int howManyAttack = 0;
        int howManyDefend = 0;
        
        //computation of armies that can attack || defend
        if(defArmies>= 3){
            howManyDefend = 3;
        } else {howManyDefend = defArmies;}
        
        if(atkArmies > 3){
            howManyAttack = 3;
        } else {howManyAttack = atkArmies - 1;}
        
        // dice generation
        for(int i=0; i<howManyDefend; i++){
            defDices[i] = 1 + dice.nextInt(6);
        }
        
        for(int i=0; i<howManyAttack; i++){
            atkDices[i] = 1 + dice.nextInt(6);
        }
        
        // arrays re-arrangement for computations
        Arrays.sort(defDices);
        Arrays.sort(atkDices);
        defDices = revert(defDices);
        atkDices = revert(atkDices);
        
        // cycle for computation of died armies
        final int last = Math.min(howManyAttack, howManyDefend);
        int i = 0;
        while(i<last) {
            if(defDices[i] >= atkDices[i]) {
                atkLost++;
            } else {defLost++;}
            i++;
        } 
        
        // computation of new armies for countries
        this.removeArmies(atkLost);
        defender.removeArmies(defLost);
    }
    
    /**
     * The following methods add listeners for CountryListener
     */
    public final void addCountryListener(final CountryListener li){
        listeners.add(li);
    }
    
    public final void removeCountryListener(final CountryListener li){
        listeners.remove(li);
    }
    
    /**
     * Notices when something changed on a Country.
     */
    public void fireArmiesChanged(final Country country){
        for(final CountryListener li : listeners){
            li.armiesChanged(country);
        }
    }
}
